package com.jiesone.logger.distributecleaning.util;

import com.mysql.jdbc.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;

import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;

import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通过此操作类 ，经过清洗加工过的数据和预处理过目标数据 存储保存
 */
@Component
public class ElasticSearchUtil {

    Logger  logger = LoggerFactory.getLogger(ElasticSearchUtil.class);
    @Autowired
     RestHighLevelClient  levelClient;
    @Autowired
    SnowFlake snowFlake;

    @Autowired
    ElasticsearchRestTemplate  elasticsearchRestTemplate;

    /**
     *  判断index是否存储
     * @param index
     * @return
     * @throws IOException
     */
    public  boolean  checkIndexExist(String[]  index) throws IOException {

        GetIndexRequest      request=new GetIndexRequest(index);

     return    levelClient.indices().exists(request, RequestOptions.DEFAULT);


    }


    /**
     *
     * @param index  所以名称
     * @param shard   分片书
     * @param repl 备份说
     * @param fieldList   字段详细封装信息
     */
     public  CreateIndexResponse  createIndex(String index, int shard, int  repl, List<Map<String,Object>> fieldList) throws IOException {

         CreateIndexRequest request  =new CreateIndexRequest(index);
         request.settings(Settings.builder().put("index.number_of_shards",shard).put("index.number_of_replicas",repl));

         Map<String, Object> properties = new HashMap<>();
         for (Map<String,Object> map: fieldList){
             /****
              * 封装字段类型 start
              */
             Map<String, Object> message = new HashMap<>();
             message.put("type",map.get("field_value").toString());
             //设置字段是否支持分组查询    占磁盘空间
//            if(map.get("fileddata").equals(true)){
//                message.put("fileddata","enabled");
//            }

//            if(map.get("enabled").equals(true)){
//                message.put("enabled",true);
//            }



             //设置字段是否索引
             if(map.get("index").equals(true)){
                 message.put("index",true);
             }
             //  设置日期格式
             if(map.get("field_value").toString().equals("date")&&!map.get("field_formart").equals(null)){
                 message.put("format",map.get("field_formart").toString());
             }

             // 设置字段名称
             properties.put(map.get("field_name").toString(), message);

             /****
              * 封装字段类型  end
              */
         }

         Map<String, Object> mapping = new HashMap<>();
         mapping.put("properties", properties);

       logger.debug("mapping----->"+mapping);


         request.settings(Settings.builder().put("index.number_of_shards",shard).put("index.number_of_replicas",repl));
         request.mapping(mapping);
         CreateIndexResponse indexResponse= levelClient.indices().create(request, RequestOptions.DEFAULT);
       return  indexResponse;

     }


    public IndexResponse insertOrUpdateOne(String index,long id, Map entityJson)  throws  Exception {
        IndexRequest request = new IndexRequest(index.toLowerCase());
        request.id(String.valueOf(id));
        request.source(entityJson);
        IndexResponse insetReponse = levelClient.index(request, RequestOptions.DEFAULT);



        return insetReponse;

    }
    public IndexResponse insertOrUpdateOne(String index, Map entityJson)  throws  Exception {
        IndexRequest request = new IndexRequest(index.toLowerCase());
        request.id(String.valueOf(snowFlake.nextId()));
        request.source(entityJson);
        IndexResponse insetReponse = levelClient.index(request, RequestOptions.DEFAULT);

        return insetReponse;

    }

    public IndexResponse insertOrUpdateOne(String index, String entityJson)  throws  Exception {
        IndexRequest request = new IndexRequest(index.toLowerCase());
        request.id(String.valueOf(snowFlake.nextId()));
        request.source(entityJson, XContentType.JSON);

        IndexResponse insetReponse = levelClient.index(request, RequestOptions.DEFAULT);

        return insetReponse;

    }

    /**
     *
     * @param index 待删除 index 名称
     * @return
     * @throws Exception
     */
    public boolean   deleteIndex(String... index   )  throws  Exception {
        DeleteIndexRequest deleteRequest=new DeleteIndexRequest();
         deleteRequest.indices(index);
        AcknowledgedResponse de = levelClient.indices().delete(deleteRequest, RequestOptions.DEFAULT);
        return    de.isAcknowledged();

    }
    public void  deleteIndexData(String index,long
                                 id)  throws  Exception {
        DeleteRequest request = new DeleteRequest();
              request.index(index.toLowerCase());
                request.id(String.valueOf(id));

              levelClient.delete(request,RequestOptions.DEFAULT);

         DeleteIndexRequest deleteRequest=new DeleteIndexRequest(index);
        levelClient.indices().delete(deleteRequest,RequestOptions.DEFAULT);

    }

    public void  search(Map<String,Object> searchMap,String  index, String  rangeKey,Object rangeValue,Object endrangeValue,int size,int page,String sortKey) throws IOException {

        SearchRequest searchRequest = new SearchRequest();

              searchRequest.indices(index.toLowerCase())    ;    //设置查询索引名称

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.sort(sortKey,SortOrder.DESC);// 通过ID倒序排列

          for (String key:searchMap.keySet()) {
              //查询包含关键词字段的文档：如下，表示查询出来所有包含key字段且key字段包含【相应值】值的文档
              if(searchMap.get(key).equals(null)&&!searchMap.get(key).equals("")){
                  searchSourceBuilder.query(QueryBuilders.fuzzyQuery(key,searchMap.get(key)));
                  searchSourceBuilder.query(QueryBuilders.termQuery(key,searchMap.get(key)));
              }
          }
          //区间查询   true  代表 包含临界点
        searchSourceBuilder.query(QueryBuilders.rangeQuery(rangeKey).from(rangeValue,true).to(endrangeValue,true));

           //分页业务封装
        searchSourceBuilder.size(size).from(PageRequest.of(page,size).getPageNumber());

        SearchResponse response = levelClient.search(searchRequest, RequestOptions.DEFAULT);

    }


    public SearchHits searchQuery(Map<String,Object> searchMap, String  index ) throws IOException {

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(index.toLowerCase())    ;    //设置查询索引名称
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        for (String key:searchMap.keySet()) {
            //查询包含关键词字段的文档：如下，表示查询出来所有包含key字段且key字段包含【相应值】值的文档
            if(!searchMap.get(key).equals(null)&&!searchMap.get(key).equals("")){
                searchSourceBuilder.query(QueryBuilders.matchQuery(key,searchMap.get(key)));
            //    searchSourceBuilder.query(QueryBuilders.termQuery(key,searchMap.get(key)));
            }
        }
        SearchResponse response = levelClient.search(searchRequest.source(searchSourceBuilder), RequestOptions.DEFAULT);
        return response.getHits();

    }


    public Map search(Map<String, String> searchMap) {

        Map<String, Object> resultMap = new HashMap<>();

//构建查询
        if (searchMap != null) {
            //构建查询条件封装对象
            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            //按照关键字查询
            if (!StringUtils.isNullOrEmpty(searchMap.get("keywords"))) {
                boolQuery.must(QueryBuilders.matchQuery("name", searchMap.get("keywords")).operator(Operator.AND));
            }

            //按照品牌进行过滤查询
            if (!StringUtils.isNullOrEmpty(searchMap.get("brand"))) {
                boolQuery.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand")));
            }

            //按照规格进行过滤查询
            for (String key : searchMap.keySet()) {
                if (key.startsWith("spec_")) {
                    String value = searchMap.get(key).replace("%2B", "+");
                    //spec_网络制式
                    boolQuery.filter(QueryBuilders.termQuery(("specMap." + key.substring(5) + ".keyword"), value));
                }
            }

            //按照价格进行区间过滤查询
            if (!StringUtils.isNullOrEmpty(searchMap.get("price"))) {
                String[] prices = searchMap.get("price").split("-");
                // 0-500 500-1000
                if (prices.length == 2) {
                    boolQuery.filter(QueryBuilders.rangeQuery("price").lte(prices[1]));
                }
                boolQuery.filter(QueryBuilders.rangeQuery("price").gte(prices[0]));
            }
            nativeSearchQueryBuilder.withQuery(boolQuery);

            //按照品牌进行分组(聚合)查询
            String skuBrand = "skuBrand";
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field("brandName"));

            //按照规格进行聚合查询
            String skuSpec = "skuSpec";
            nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field("spec.keyword"));

            //开启分页查询
            String pageNum = searchMap.get("pageNum"); //当前页
            String pageSize = searchMap.get("pageSize"); //每页显示多少条
            if (StringUtils.isNullOrEmpty(pageNum)) {
                pageNum = "1";
            }
            if (StringUtils.isNullOrEmpty(pageSize)) {
                pageSize = "20";
            }

            //设置分页
            //第一个参数:当前页 是从0开始
            //第二个参数:每页显示多少条
            nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1, Integer.parseInt(pageSize)));

            //按照相关字段进行排序查询
            // 1.当前域 2.当前的排序操作(升序ASC,降序DESC)
            if (!StringUtils.isNullOrEmpty(searchMap.get("sortField")) && !StringUtils.isNullOrEmpty(searchMap.get("sortRule"))) {
                if ("ASC".equals(searchMap.get("sortRule"))) {
                    //升序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.ASC));
                } else {
                    //降序
                    nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get("sortField"))).order(SortOrder.DESC));
                }
            }

            return null;
        }


        /**
         * 原有数据
         *  [
         *         "{'颜色': '黑色', '尺码': '平光防蓝光-无度数电脑手机护目镜'}",
         *         "{'颜色': '红色', '尺码': '150度'}",
         *         "{'颜色': '黑色', '尺码': '150度'}",
         *         "{'颜色': '黑色'}",
         *         "{'颜色': '红色', '尺码': '100度'}",
         *         "{'颜色': '红色', '尺码': '250度'}",
         *         "{'颜色': '红色', '尺码': '350度'}",
         *         "{'颜色': '黑色', '尺码': '200度'}",
         *         "{'颜色': '黑色', '尺码': '250度'}"
         *     ]
         *
         *    需要的数据格式
         *    {
         *        颜色:[黑色,红色],
         *        尺码:[100度,150度]
         *    }
         */

      return null;
    }



}
